﻿using System.Collections;
using System.Collections.Generic;

//------------------------------------------------------------
// shaco Framework
// Copyright © 2017-2021 chang.liu All rights reserved.
// Feedback: 449612236@qq.com
//------------------------------------------------------------

namespace shaco.Base
{
    public class WaitFor
    {
        private class InvokeInfo
        {
            public float currentSeconds = 0;
            public System.Func<bool> callbackIn = null;
            public System.Action callbackOut = null;

        }
        static private List<InvokeInfo> _invokes = new List<InvokeInfo>();
        static private shaco.Base.IObjectPool _objectPool = null;

        /// <summary>
        /// 计时器刷新函数
        /// </summary>
        static public void Update(float deltaTime)
        {
            if (_invokes.Count > 0)
            {
                for (int i = _invokes.Count - 1; i >= 0; --i)
                {
                    var invokeInfo = _invokes[i];
                    bool result = false;

                    try
                    {
                        invokeInfo.currentSeconds += deltaTime;
                        result = invokeInfo.callbackIn();
                    }
                    catch (System.Exception e)
                    {
                        Log.Error("WaitFor exception: InTarget" + invokeInfo.callbackIn.Target + " InMethod" + invokeInfo.callbackIn.Method + " e=" + e);
                        _objectPool.RecyclingObject(invokeInfo);
                        _invokes.RemoveAt(i);
                        continue;
                    }
                    if (result)
                    {
                        try
                        {
                            // if (shaco.Base.GameHelper.objectpool.IsInstantiated(invokeInfo))
                            _objectPool.RecyclingObject(invokeInfo);
                            _invokes.RemoveAt(i);

                            GameHelper.profiler.BeginSample("WaitFor callbackOut: target=" + invokeInfo.callbackOut.Target + " method=" + invokeInfo.callbackOut.Method);
                            {
                                invokeInfo.callbackOut();
                            }
                            GameHelper.profiler.EndSample();
                        }
                        catch (System.Exception e)
                        {
                            Log.Error("WaitFor exception: OutTarget=" + invokeInfo.callbackOut.Target + " OutMethod=" + invokeInfo.callbackOut.Method + " e=" + e);
                            continue;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 开启一个条件计时器
        /// <param name="callbackIn">条件判断方法</param>
        /// <param name="callbackOut">条件执行方法，条件判断方法返回true的时候执行</param>
        /// </summary>
        static public void Run(System.Func<bool> callbackIn, System.Action callbackOut)
        {
            if (null == _objectPool)
                _objectPool = shaco.Base.GameHelper.objectpool;

            //如果非unity引擎，需要手动调用shaco.Base.WaitFor.Update来执行计时器
            var invokeInfo = _objectPool.Instantiate(() => new InvokeInfo());
            invokeInfo.currentSeconds = 0;
            invokeInfo.callbackIn = callbackIn;
            invokeInfo.callbackOut = callbackOut;

            _invokes.Add(invokeInfo);
        }

        /// <summary>
        /// 开启一个时间计时器
        /// <param name="callbackOut">到达指定时间</param>
        /// <param name="waitSeconds">等待时间(秒)</param>
        /// </summary>
        static public void Run(System.Action callbackOut, float waitSeconds)
        {
            if (waitSeconds <= 0)
            {
                callbackOut();
                return;
            }

            if (null == _objectPool)
                _objectPool = shaco.Base.GameHelper.objectpool;

            //如果非unity引擎，需要手动调用shaco.Base.WaitFor.Update来执行计时器
            var invokeInfo = _objectPool.Instantiate(() => new InvokeInfo());
            invokeInfo.currentSeconds = 0;
            invokeInfo.callbackIn = () =>
            {
                return invokeInfo.currentSeconds >= waitSeconds;
            };
            invokeInfo.callbackOut = callbackOut;
            _invokes.Add(invokeInfo);
        }

        static public void StopAll()
        {
            foreach (var iter in _invokes)
            {
                if (shaco.Base.GameHelper.objectpool.IsInPool(iter))
                    iter.DestroyWithPool();
            }
            _invokes.Clear();
        }
    }
}
